package com.un.ebs.core.util;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.reflect.ActualTypeMapperPool;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.TypeUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.un.ebs.core.UserContextService;
import com.un.ebs.core.enums.DataTypeEnum;
import com.un.ebs.core.enums.IEnum;
import com.un.ebs.core.enums.RequestArgEnum;
import com.un.ebs.core.enums.ServiceTypeEnum;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.metadata.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.ibatis.logging.Log;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.*;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.stream.Stream;

//import com.un.ebs.sys.service.DictionaryValueService;

@Component
public class PackageUtil {

    public static final String defaultPackageName = "com.un";
    /**
     * jar中的文件路径分隔符
     */
    private static final char SLASH_CHAR = '/';
    /**
     * 包名分隔符
     */
    private static final char DOT_CHAR = '.';
    private static PackageUtil packageUtil;
    private static ApplicationContext applicationContext;
    private static UserContextService userContextService;

    /**
     * 获取指定包中，所有包含 @RestController 注解的 class，并将其以 ServiceInfo 的数据结构返回
     *
     * @param packageName
     * @return
     */
    public static List<ServiceInfo> getControllers(String packageName) {

        List<ServiceInfo> result = new ArrayList<>();

        // 反射加载，原生服务
        for (Class<?> cls : PackageUtil.getClass(packageName, true)) {
            RestController controller = cls.getAnnotation(RestController.class);
            if (controller != null) {
                ServiceInfo s = getController(cls);
                s.setServiceType(ServiceTypeEnum.Native);
                result.add(s);
            }
        }

        // 数据库加载，标准服务
        result.addAll(
                applicationContext.getBeansOfType(ServiceExt.class)
                        .entrySet()
                        .stream()
                        .flatMap(
                                x -> {
                                    try {
                                        return x.getValue().queryServices().stream();
                                    } catch (Exception ex) {
                                        System.out.println(ex.getMessage());
                                        return new ArrayList<ServiceInfo>().stream();
                                    }
                                }
                        )
                        .collect(Collectors.toList())
        );

        result.stream().sorted(Comparator.comparing(ServiceInfo::getName)).collect(Collectors.toList());
        return result;
    }

    public static List<FunctionInfo> getServiceFunctionExt(String serviceName) {
        List<FunctionInfo> ret = new ArrayList<>();

        applicationContext.getBeansOfType(ServiceFunctionExt.class)
                .entrySet()
                .stream()
                .forEach(x -> {
                    ServiceInfoExt ann = x.getValue().getClass().getAnnotation(ServiceInfoExt.class);
                    if (ann != null) {
                        Type argType = ((ParameterizedTypeImpl) x.getValue().getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
                        Class argClass = null;
                        try {
                            argClass = Class.forName(argType.getTypeName());
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }

                        Method m = ReflectUtil.getMethodByName(x.getValue().getClass(),"exec");

                        ret.add(new FunctionInfo(
                                ann.functionName(),
                                "/common/" + ann.value() + "/ext/" + ann.functionName(),
                                ann.functionDesc(),
                                RequestMethod.POST,
                                getRequestArg(argClass, m.getParameters()[0].getName()),
                                getResponse(m)));
                    }
                });
        return ret;
    }

    public static List<RequestArg> getRequestArg(Class argClass, String argName) {
        DataTypeEnum dt = getDataType(argClass);
        if (dt == DataTypeEnum.OBJECT) {
            return getRequest(getMetadata(argClass, null));
        }

        List<RequestArg> args = new ArrayList<>();
        RequestArg arg = new RequestArg();
        arg.setDataType(dt);
        arg.setName(argName);
        arg.setRequestType(RequestArgEnum.RequestBody);
        args.add(arg);
        return args;
    }

    /**
     * 获取指定包中，所有实现了 IEnum 接口的枚举类型
     *
     * @param packageName
     * @return
     */
    public static Map<String, List<EnumInfo>> getEnums(String packageName) {
        if (StringUtils.isNullOrEmpty(packageName)) {
            packageName = defaultPackageName;
        }

        Map<String, List<EnumInfo>> map = new HashMap<>();
        List<Class<?>> list = PackageUtil.getClass(packageName, true);
        for (Class<?> cls : list) {
            if (cls.getName().equals("com.un.ebs.core.enums.ConfigureValueTypeEnum")) {
                System.out.println(1);
            }
            if (!cls.isEnum()) {
                continue;
            }
            //System.out.println(cls.getTypeName());
            if (IEnum.class.isAssignableFrom(cls)) {
                map.put(cls.getName(), getEnums(cls));
            } else {
                LoggerFactory.getLogger(PackageUtil.class).warn("枚举类型 " + cls.getName() + " 没有实现 IEnum 接口, 将不能被被前端调用.");
            }
        }
        return map;
    }

    public static List<EnumInfo> getEnums(Class enumType) {

        List<EnumInfo> result = new ArrayList<>();
        if (!enumType.isEnum()) {
            return result;
        }

        try {
            Method m = enumType.getMethod("values");
            com.un.ebs.core.enums.IEnum[] enums = (com.un.ebs.core.enums.IEnum[]) m.invoke(null);
            for (com.un.ebs.core.enums.IEnum e : enums) {
                //if(e.isJsonIgonre()) continue;
                //result.add(new EnumInfo(e.toString(),e.getLabel()));
                result.add(new EnumInfo(e.toString(), e.getCode(), e.getDesc()));
            }
        } catch (ClassCastException ex) {
            LoggerFactory.getLogger(PackageUtil.class).error(enumType.getName() + " 没有实现IEnum接口");
        } catch (Exception ex) {
            LoggerFactory.getLogger(PackageUtil.class).error("加载枚举类型异常.", ex);
        }
        return result;
    }

    public static String getTypeName(String typeName) {
        if (StringUtils.isNullOrEmpty(typeName)) {
            return null;
        }

        if (typeName.indexOf("<") > 0) {
            return typeName.substring(0, typeName.indexOf("<"));
        } else {
            return typeName;
        }
    }

    public static String getFirstParameterizedType(String typeName) {
        if (StringUtils.isNullOrEmpty(typeName)) {
            return null;
        }

        if (typeName.indexOf("<") > 0) {
            return typeName.substring(typeName.indexOf("<") + 1, typeName.length() - 1);
        } else {
            return null;
        }

    }

    /**
     * 在当前项目中寻找指定包下的所有类
     *
     * @param packageName 用'.'分隔的包名
     * @param recursive   是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClass(String packageName, boolean recursive) {
        if (StringUtils.isNullOrEmpty(packageName)) {
            packageName = defaultPackageName;
        }
        List<Class<?>> classList = new ArrayList<Class<?>>();
        try {
            //获取当前线程的类装载器中相应包名对应的资源
            Enumeration<URL> iterator = Thread.currentThread().getContextClassLoader().getResources(packageName.replace(DOT_CHAR, File.separatorChar));
            while (iterator.hasMoreElements()) {
                URL url = iterator.nextElement();
                String protocol = url.getProtocol();
                //System.out.println(protocol);
                List<Class<?>> childClassList = Collections.emptyList();
                switch (protocol) {
                    case "file":
                        childClassList = getClassInFile(url, packageName, recursive);
                        break;
                    case "jar":
                        childClassList = getClassInJar(url, packageName, recursive);
                        break;
                    default:
                        //在某些WEB服务器中运行WAR包时，它不会像TOMCAT一样将WAR包解压为目录的，如JBOSS7，它是使用了一种叫VFS的协议
                        System.out.println("unknown protocol " + protocol);
                        break;
                }
                classList.addAll(childClassList);
            }
            return classList;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    public static ServiceInfo getController(Class<?> cls) {
        RestController controllerAnnotation = cls.getAnnotation(RestController.class);
        if (controllerAnnotation == null) {
            return null;
        }

        Api api = cls.getAnnotation(Api.class);
        RequestMapping requestMapping = cls.getAnnotation(RequestMapping.class);
        return new ServiceInfo(
                api == null ? cls.getName() : api.value(),
                org.apache.commons.lang3.StringUtils.join(requestMapping.value(), ","),
                controllerAnnotation.value(),
                cls.getTypeName(),
                null);
    }

    public static List<FunctionInfo> getFunctions(String serviceName) {
        List<FunctionInfo> ret = new ArrayList<>();
        Optional<ServiceInfo> serviceInfo = PackageUtil.getControllers(null).stream().filter(s -> s.name.equals(serviceName)).findFirst();
        if (!serviceInfo.isPresent()) {
            throw new BusinessException("指定的服务 【 " + serviceName + " 】 没有找到。");
        }

        if (serviceInfo.get().isDynamic) {
            // 标准服务
            applicationContext.getBeansOfType(ServiceExt.class).entrySet().stream()
                    .forEach(s -> {
                        ret.addAll(s.getValue().queryFunctions(serviceName));
                    });

            // 标准服务扩展
            ret.addAll(PackageUtil.getServiceFunctionExt(serviceName));
        } else {
            // 原生服务
            try {
                ret.addAll(PackageUtil.getFunctions(Class.forName(serviceInfo.get().getTypeName())));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                throw new BusinessException("获取接口定义失败：" + e.getMessage());
            }
        }

        return ret;
    }

    /**
     * 获取一个 class 中所有包含 @RequestMapping 注解的 method ，并将其以 FunctionInfo 的数据结构返回
     *
     * @param cls
     * @return
     */
    public static List<FunctionInfo> getFunctions(Class<?> cls) {
        List<FunctionInfo> result = new ArrayList();
        String rootPathName = null;
        if (cls.getAnnotation(RequestMapping.class).value().length <= 0) {
            return null;
        }

        rootPathName = cls.getAnnotation(RequestMapping.class).value()[0];

        for (Method m : cls.getMethods()) {
            String name = null;
            RequestMapping requestMapping = m.getAnnotation(RequestMapping.class);
            ApiOperation apiOperation = m.getAnnotation(ApiOperation.class);

            List<RequestMethod> methods = new ArrayList();
            if (requestMapping != null) {
                name = requestMapping.value()[0];
                methods.addAll(Arrays.stream(requestMapping.method()).collect(Collectors.toList()));
            } else {
                PostMapping postMapping = m.getAnnotation(PostMapping.class);
                if (postMapping != null) {
                    methods.add(RequestMethod.POST);
                    name = postMapping.value()[0];
                } else {
                    GetMapping getMapping = m.getAnnotation(GetMapping.class);
                    if (getMapping != null) {
                        methods.add(RequestMethod.GET);
                        name = getMapping.value()[0];
                    } else {
                        continue;
                    }
                }
            }
            String apiDesc = null;
            if (apiOperation != null) {
                if (name.equals(apiOperation.value())) {
                    apiDesc = apiOperation.notes();
                } else {
                    apiDesc = apiOperation.value();
                }
            }

            rootPathName = rootPathName.replace("/*", "");
            if (!rootPathName.startsWith("/"))
                rootPathName = "/" + rootPathName;

            if (name.startsWith("/")) {
                name = rootPathName + name;
            } else {
                name = rootPathName + "/" + name;
            }

            result.add(new FunctionInfo(
                    m.getName(),
                    name,
                    apiDesc,
                    methods.get(0),
                    getRequest(m),
                    getResponse(m))
            );
        }
        return result.stream().sorted(Comparator.comparing(FunctionInfo::getName)).collect(Collectors.toList());
    }

    /**
     * 获取没有controller的且继承了ServiceExt的function
     *
     * @param serviceName
     * @return
     */
    public static List<FunctionInfo> getOtherFunctions(String serviceName) {

        List<FunctionInfo> result = applicationContext.getBeansOfType(ServiceExt.class)
                .entrySet()
                .stream()
                .flatMap(x -> {
                    try {
                        return x.getValue().queryFunctions(serviceName).stream();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                        //System.out.println(ex.getMessage());
                        return new ArrayList<FunctionInfo>().stream();
                    }
                }).collect(Collectors.toList());

        if (result.size() <= 0 || result == null) {
            throw new BusinessException("指定的服务 【 " + serviceName + " 】 没有找到。");
        }
        return result;
    }

    /**
     * 判断是否为泛型
     *
     * @param typeName
     * @return
     */
    public static boolean isGenericeType(String typeName) {
        return typeName.indexOf("<") > 0;
    }

    /**
     * 是否为Java基本类型
     * @param typeName
     * @return
     */
    public static boolean isJavaBaseType(String typeName){
        if (typeName.equals(String.class.getTypeName())){
            return true;
        }else if(typeName.equals(Integer.class.getTypeName())){
            return true;
        }else if(typeName.equals(int.class.getTypeName())){
            return true;
        }else if(typeName.equals(Double.class.getTypeName())){
            return true;
        }else if(typeName.equals(double.class.getTypeName())){
            return true;
        }else if(typeName.equals(Boolean.class.getTypeName())){
            return true;
        }else if(typeName.equals(boolean.class.getTypeName())){
            return true;
        }else if(typeName.equals(Date.class.getTypeName())){
            return true;
        }else return typeName.equals(DateTime.class.getTypeName());
    }

    /**
     * 是否为数组
     *
     * @param typeName
     * @return
     */
    public static boolean isArray(String typeName) {
        return List.class.getName().equals(getTypeName(typeName));
    }

    public static List<RequestArg> getRequest(List<MetadataField> list) {
        List<RequestArg> ret = new ArrayList<>();
        for (MetadataField arg : list) {
            RequestArg obj = new RequestArg();
            obj.setRequestType(RequestArgEnum.RequestBody);
            BeanUtils.copyProperties(arg, obj);
            ret.add(obj);
        }
        return ret;
    }

    /**
     * 获取 method 输入参数的数据结构
     *
     * @param method
     * @return
     */
    public static List<RequestArg> getRequest(Method method) {
        if (method.getParameterCount() <= 0) {
            return null;
        }

        List<RequestArg> result = new ArrayList<>();
        for (Parameter p : method.getParameters()) {
            RequestArg arg = new RequestArg();
            arg.setName(p.getName());
            arg.setDisplayName(p.getName());
            arg.setIsArray(0);

            if (p.getParameterizedType() != null) {
                if (isArray(p.getParameterizedType().getTypeName())) {
                    arg.setDataType(getDataType(getFirstParameterizedType(p.getParameterizedType().getTypeName())));
                    arg.setIsArray(1);
                } else {
                    arg.setDataType(getDataType(p.getType(), p.getParameterizedType()));
                }
            } else {
                arg.setDataType(getDataType(p.getType(), p.getParameterizedType()));
            }

            if (p.getType().isEnum()) {
                arg.setResourceData(ResourceData.fromEnum(p.getType()));
            }
            if (p.getAnnotation(Resource.class) != null) {
                Resource res = p.getAnnotation(Resource.class);
                arg.setDataType(DataTypeEnum.RESOURCE_DATA);
                arg.setResourceCode(res.key());
                arg.setResourceType(res.type());
                if (ResourceType.Dictionary.equals(res.type())) {
                    arg.setResourceData(getUserContextService().queryDictionKey(res.key()));
                }
            }

            if (p.getDeclaredAnnotation(RequestParam.class) != null) {
                if (p.getType().getTypeName().equals(MultipartFile.class.getTypeName())) {
                    arg.setRequestType(RequestArgEnum.RequestParamFile);
                } else {
                    arg.setRequestType(RequestArgEnum.RequestParam);
                }
            } else if (p.getDeclaredAnnotation(RequestBody.class) != null) {
                arg.setRequestType(RequestArgEnum.RequestBody);
            } else if (p.getDeclaredAnnotation(PathVariable.class) != null) {
                arg.setRequestType(RequestArgEnum.PathVariable);
            } else {
                //arg.setRequestType(RequestArgEnum.Nothing);
                arg.setRequestType(RequestArgEnum.RequestBody);
            }

            if (arg.getDataType() == DataTypeEnum.OBJECT) {
                if (p.getParameterizedType() instanceof ParameterizedType) {
                    String typeName = null;
                    if (isArray(p.getParameterizedType().getTypeName())) {
                        typeName = getFirstParameterizedType(p.getParameterizedType().getTypeName());
                    } else {
                        typeName = p.getParameterizedType().getTypeName();
                    }
                    try {
                        arg.setChildField(getMetadata(Class.forName(typeName), null));
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                } else {
                    arg.setChildField(getMetadata(p.getType(), null));
                }
            }

            result.add(arg);
        }

        return result;
    }

    /**
     * 获取 method 返回值的数据结构
     *
     * @param m class.method 对象
     * @return 返回值的数据结构
     */
    public static List<MetadataField> getResponse(Method m) {
        if (Void.class.getName().equals(m.getReturnType().getName())) {
            return null;
        }

        ParameterizedType pt = null;
        String typeName = null;

        if (m.getGenericReturnType() instanceof ParameterizedType) {
            pt = ((ParameterizedType) m.getGenericReturnType());
            typeName = pt.getTypeName();
        }

        DataTypeEnum dt = getDataType(m.getReturnType());
        if (dt != DataTypeEnum.OBJECT) {
            List<MetadataField> ret = new ArrayList<>();
            MetadataField f = new MetadataField();
            f.setName("defaultValue");
            f.setDataType(dt);
            ret.add(f);
            return ret;
        }

        try {
            return getMetadata(m.getReturnType(), typeName);
        } catch (Exception ex) {
            return null;
        }
    }

    public static void main(String[] args) {
        List<MetadataField> list = getMetadata(Query.class, "com.un.ebs.core.metadata.Query");
        for (MetadataField m : list) {
            System.out.println(m.toString());
        }
    }

    public static List<MetadataField> getMetadata(Class cls, String genericTypeName) {
        if (getDataType(cls) != DataTypeEnum.OBJECT) {
            System.out.println("getMetadata 仅支持 OBJECT 类型。");
            return null;
        }
        List<MetadataField> ret = new ArrayList<>();
        try {

            if (cls.isInterface() && IPage.class.getName().equals(cls.getTypeName())) {
                cls = Page.class;
            }
            if (Void.class.getName().equals(cls.getTypeName())) {
                return null;
            }

            for (Field f : getClassField(cls)) {
                if (Log.class.getName().equals(f.getType().getName())) {
                    continue;
                }
                if ("serialVersionUID".equals(f.getName())) {
                    continue;
                }

                MetadataField obj = new MetadataField();
                obj.setName(f.getName());
                obj.setIsArray(0);
                obj.setNull(true);
                obj.setLength(0);
                NotNull n = f.getAnnotation(NotNull.class);
                if (n != null) {
                    obj.setNull(false);
                }

                if (f.getType().isEnum()) {
                    obj.setResourceData(ResourceData.fromEnum(f.getType()));
                }

                //数据类型验证
                if (f.getGenericType().getTypeName().equals("T")) {
                    if (!StringUtils.isNullOrEmpty(genericTypeName)) {
                        obj.setDataType(DataTypeEnum.OBJECT);
                    } else {
                        //LoggerFactory.getLogger(PackageUtil.class).warn("泛型类型对象（" + cls.getTypeName() + "）没有指定具体的泛型参数类型，将默认为 String 类型。");
                        obj.setDataType(DataTypeEnum.STRING);
                    }
                } else {
                    obj.setDataType(getDataType(f.getType()));
                }

                if (f.getAnnotation(Resource.class) != null) {
                    Resource res = f.getAnnotation(Resource.class);
                    obj.setDataType(DataTypeEnum.RESOURCE_DATA);
                    obj.setResourceType(res.type());
                    obj.setResourceCode(res.key());
                    obj.setIsArray(isArray(f.getType().getTypeName()) ? 1 : 0);

                    if (ResourceType.Dictionary.equals(res.type())) {
                        obj.setResourceData(getUserContextService().queryDictionKey(res.key()));
                    }
                }
                if (f.getAnnotation(PackageIgnore.class) != null) {
                    break;
                }

                //根据数据类型处理 ChildField 集合
                if (obj.getDataType() == DataTypeEnum.OBJECT) {
                    String typeName = null;

                    if (f.getName().equals("roleIds")) {
                        System.out.println(".");
                    }

                    // 泛型
                    if (f.getGenericType().getTypeName().equals("T") || isGenericeType(f.getGenericType().getTypeName())) {

                        // pt 必须有值
                        if (StringUtils.isNullOrEmpty(genericTypeName)) {
                            //throw new BusinessException("没有指定泛型类型 : " + f.getGenericType().getTypeName());
                            genericTypeName = f.getGenericType().getTypeName();
                        }

                        typeName = getFirstParameterizedType(genericTypeName);
                        if (getDataType(typeName) == DataTypeEnum.OBJECT) {
                            if (isGenericeType(typeName)) {
                                if (isArray(typeName)) {
                                    obj.setIsArray(1);
                                    typeName = getFirstParameterizedType(typeName);
                                } else {
                                    obj.setIsArray(0);
                                }
                                obj.setChildField(getMetadata(Class.forName(getTypeName(typeName)), typeName));

                            } else {
                                if (isArray(f.getGenericType().getTypeName())) {
                                    obj.setIsArray(1);
                                } else {
                                    obj.setIsArray(0);
                                }
                                obj.setChildField(getMetadata(Class.forName(typeName), null));
                            }
                        }
                    } else if (cls.getName().equals(String.class.getName())) {
                        obj.setDataType(DataTypeEnum.STRING);
                    } else {
                        LoggerFactory.getLogger(PackageUtil.class).warn("不是泛型参数，类型被忽略： [ " + cls.getName() + " ] " + f.getName() + " : " + f.getType());
                    }
                }
                ret.add(obj);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return ret;
    }

    public static List<ClassInfo> getClassInfo(Class cls) {
        List<ClassInfo> result = new ArrayList<>();
        for (Method m : cls.getMethods()) {
            if ("getClass".equals(m.getName())) {
                continue;
            }
            if (!"get".equals(m.getName().substring(0, 3))) {
                continue;
            }
            if ("get".equals(m.getName())) {
                continue;
            }
            if ("void".equals(m.getReturnType().getName())) {
                continue;
            }
            result.add(getClassInfo(m.getName(), m.getReturnType()));
        }
        return result;
    }

    private static ClassInfo getClassInfo(String name, Class<?> cls) {
        ClassInfo clsInfo = new ClassInfo();
        clsInfo.setName(name.replace("get", ""));
        clsInfo.setName(clsInfo.getName().substring(0, 1).toLowerCase() + clsInfo.getName().substring(1));
        clsInfo.setArray(cls.isArray());
        clsInfo.setEnum(cls.isEnum());

        if (cls.getGenericInterfaces().length > 0) {
            if (cls.getGenericInterfaces()[0] instanceof ParameterizedType) {
                clsInfo.setGenericType(true);
                clsInfo.setType(DataTypeEnum.OBJECT);
                ParameterizedType pt = ((ParameterizedType) cls.getGenericInterfaces()[0]);
                for (Type t : pt.getActualTypeArguments()) {
                    System.out.println(t.getTypeName());
                }
                clsInfo.setChilds(getClassInfo(pt.getActualTypeArguments().getClass()));
            } else {
                clsInfo.setType(getDataType(cls, null));
                clsInfo.setChilds(getClassInfo(cls));
            }
        } else {
            clsInfo.setType(getDataType(cls, null));
            clsInfo.setChilds(getClassInfo(cls));
        }

        return clsInfo;
    }

    private static List<Field> getClassField(Class cls) {
        List<Field> result = new ArrayList(Arrays.asList(cls.getDeclaredFields()));
        if (cls.getSuperclass() != null) {
            result.addAll(getClassField(cls.getSuperclass()));
        }
        return result;
    }

    public static DataTypeEnum getDataType(Class cls, Type pt) {
        return getDataType(cls);
    }

    public static DataTypeEnum getDataType(String typeName) {
        if (StringUtils.isNullOrEmpty(typeName)) {
            return DataTypeEnum.NONE;
        } else if (typeName.equals(String.class.getName())) {
            return DataTypeEnum.STRING;
        } else if (typeName.equals(int.class.getName())) {
            return DataTypeEnum.INT;
        } else if (typeName.equals(Integer.class.getName())) {
            return DataTypeEnum.INT;
        } else if (typeName.equals(Date.class.getName())) {
            return DataTypeEnum.DATE;
        } else if (typeName.equals(double.class.getName())) {
            return DataTypeEnum.NUMBER;
        } else if (typeName.equals(Double.class.getName())) {
            return DataTypeEnum.NUMBER;
        } else if (typeName.equals(Float.class.getName()) || typeName.equals(float.class.getName())) {
            return DataTypeEnum.NUMBER;
        } else if (typeName.equals(long.class.getName()) || typeName.equals(Long.class.getName())) {
            return DataTypeEnum.NUMBER;
        } else if (typeName.equals(boolean.class.getName()) || typeName.equals(Boolean.class.getName())) {
            return DataTypeEnum.BOOLEAN;
        } else if (typeName.equals(List.class.getTypeName())) {
            return DataTypeEnum.OBJECT;
        } else {
            return DataTypeEnum.OBJECT;

        }
    }

    /**
     * 将根据指定的Class类型，返回对应的描述类型
     *
     * @param cls
     * @return
     */
    public static DataTypeEnum getDataType(Class<?> cls) {
        if (cls.isEnum()) {
            return DataTypeEnum.RESOURCE_DATA;
        } else {
            return getDataType(cls.getTypeName());
        }
    }

    /**
     * 在给定的文件或文件夹中寻找指定包下的所有类
     *
     * @param url         包的统一资源定位符
     * @param packageName 用'.'分隔的包名
     * @param recursive   是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInFile(URL url, String packageName, boolean recursive) {
        try {
            Path path = Paths.get(url.toURI());
            return getClassInFile(path, packageName, recursive);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 在给定的文件或文件夹中寻找指定包下的所有类
     *
     * @param path        包的路径
     * @param packageName 用'.'分隔的包名
     * @param recursive   是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInFile(Path path, String packageName, boolean recursive) {
        if (!Files.exists(path)) {
            return Collections.emptyList();
        }
        List<Class<?>> classList = new ArrayList<Class<?>>();
        if (Files.isDirectory(path)) {
            if (!recursive) {
                return Collections.emptyList();
            }
            try {
                //获取目录下的所有文件
                Stream<Path> stream = Files.list(path);
                Iterator<Path> iterator = stream.iterator();
                while (iterator.hasNext()) {
                    classList.addAll(getClassInFile(iterator.next(), packageName, recursive));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            try {
                //由于传入的文件可能是相对路径, 这里要拿到文件的实际路径, 如果不存在则报IOException
                path = path.toRealPath();
                String pathStr = path.toString();
                //这里拿到的一般的"aa:\bb\...\cc.class"格式的文件名, 要去除末尾的类型后缀(.class)
                int lastDotIndex = pathStr.lastIndexOf(DOT_CHAR);
                //Class.forName只允许使用用'.'分隔的类名的形式
                String className = pathStr.replace(File.separatorChar, DOT_CHAR);
                //获取包名的起始位置
                int beginIndex = className.indexOf(packageName);
                if (beginIndex == -1) {
                    return Collections.emptyList();
                }
                className = lastDotIndex == -1 ? className.substring(beginIndex) : className.substring(beginIndex, lastDotIndex);
                classList.add(Class.forName(className));
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return classList;
    }

    /**
     * 在给定的jar包中寻找指定包下的所有类
     *
     * @param url         jar包的统一资源定位符
     * @param packageName 用'.'分隔的包名
     * @param recursive   是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInJar(URL url, String packageName, boolean recursive) {
        try {
            JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
            return getClassInJar(jar, packageName, recursive);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 在给定的jar包中寻找指定包下的所有类
     *
     * @param jar         jar对象
     * @param packageName 用'.'分隔的包名
     * @param recursive   是否递归搜索
     * @return 该包名下的所有类
     */
    public static List<Class<?>> getClassInJar(JarFile jar, String packageName, boolean recursive) {
        List<Class<?>> classList = new ArrayList<Class<?>>();
        //该迭代器会递归得到该jar底下所有的目录和文件
        Enumeration<JarEntry> iterator = jar.entries();
        while (iterator.hasMoreElements()) {
            //这里拿到的一般的"aa/bb/.../cc.class"格式的Entry或 "包路径"
            JarEntry jarEntry = iterator.nextElement();
            if (!jarEntry.isDirectory()) {
                String name = jarEntry.getName();
                //对于拿到的文件,要去除末尾的.class
                int lastDotClassIndex = name.lastIndexOf(".class");
                if (lastDotClassIndex != -1) {
                    int lastSlashIndex = name.lastIndexOf(SLASH_CHAR);
                    name = name.replace(SLASH_CHAR, DOT_CHAR);
                    if (name.startsWith(packageName)) {
                        if (recursive || packageName.length() == lastSlashIndex) {
                            String className = name.substring(0, lastDotClassIndex);
                            System.out.println(className);
                            try {
                                classList.add(Class.forName(className));
                            } catch (ClassNotFoundException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
        return classList;
    }

    private static UserContextService getUserContextService() {
        Optional<UserContextService> tokenService = applicationContext.getBeansOfType(UserContextService.class).entrySet().stream().map(s -> s.getValue()).findFirst();
        if (!tokenService.isPresent()) {
            throw new BusinessException("TokenServer Not implement.");
        }
        return tokenService.get();
    }

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        PackageUtil.applicationContext = applicationContext;
    }

    @PostConstruct
    public void init() {
        packageUtil = this;
        //packageUtil.dictService = this.dictService;
    }
}